#ifndef LISTA_H
#define LISTA_H

#include <stdbool.h>
#include <stddef.h>

/* ******************************************************************
 *                DEFINICION DE LOS TIPOS DE DATOS
 * *****************************************************************/

/* La lista está planteada como una lista de punteros genéricos. */

/* Que podra ser usada junto a otro TDA, un iterador para este tipo de listas */

typedef struct lista lista_t;

typedef struct lista_iter lista_iter_t;

/* ******************************************************************
 *                    PRIMITIVAS DE LA LISTA
 * *****************************************************************/

// Crea una lista enlazada.
// Post: devuelve una nueva lista vacía.
lista_t *lista_crear();

// Destruye la lista. Si se recibe la función destruir_dato por parámetro,
// para cada uno de los elementos de la lista llama a destruir_dato.
// Pre: la lista fue creada. destruir_dato es una función capaz de destruir
// los datos de la lista, o NULL en caso de que no se la utilice.
// Post: se eliminaron todos los elementos de la lista.
void lista_destruir(lista_t *lista, void destruir_dato(void *));

// Devuelve true si la lista esta vacia, false en caso contrario.
// Pre: la lista fue creada.
bool lista_esta_vacia(const lista_t *lista);

// Obtiene el valor del primer elemento de la lista. Si la lista tiene
// elementos, se devuelve el valor del primero, si está vacía devuelve NULL.
// Pre: la lista fue creada.
// Post: se devolvió el primer elemento de la lista, cuando no está vacía.
void *lista_ver_primero(const lista_t *lista);

// Obtiene el valor del ultimo elemento de la lista. Si la lista tiene
// elementos, se devuelve el valor del ultimo, si está vacía devuelve NULL.
// Pre: la lista fue creada.
// Post: se devolvió el ultimo elemento de la lista, cuando no está vacía.
void *lista_ver_ultimo(const lista_t *lista);

// Agrega un elemento al principio de la lista. Devuelve falso en caso de error.
// Pre: la lista fue creada
// Post: se agregó el elemento al comienzo de la lista.
bool lista_insertar_primero(lista_t *lista, void *dato);

// Agrega un nuevo elemento al final de la lista. Devuelve falso en caso de error.
// Pre: la lista fue creada.
// Post: se agregó un nuevo elemento en el fin de la lista.
bool lista_insertar_ultimo(lista_t *lista, void* valor);

// Borra el primer elemento de la lista. Si la lista esta vacia, devuelve NULL. En otro
// caso devuelve el elemento.
// Pre: la lista fue creada.
// Post: se eliminó el primer elemento de la lista. Se devolvió el elemento
// borrado o NULL si esta vacía. El largo de la lista decreció en una unidad.
void *lista_borrar_primero(lista_t *lista);

// Devuelve la cantidad de elementos en la lista.
// Pre: la lista fue creada
size_t lista_largo(const lista_t *lista);

// Ordena la lista por mergesort. Recibe una funcion de comparacion qe devuelve true si a<b.
void lista_mergeSort(lista_t* lista, bool funcion_comparacion(void* elementoA, void* elementoB));

// Desordena la lista aleatoriamente.
void lista_shuffle(lista_t* lista);

// Devuelve una lista que es igual al pasado por parametro.
// Pre: Recibe una lista.
// Post: Devuelve una lista identica.
lista_t* lista_clonar(const lista_t* lista);

/* ******************************************************************
 *                    PRIMITIVAS DEL ITERADOR
 * *****************************************************************/

// Crea un iterador para la lista enlazada.
// PRE: la lista fue creada.
// POST: Devuelve un iterador.
lista_iter_t *lista_iter_crear(const lista_t *lista);

// Avanza un elemento en la lista asignada. Devuelve true si la operacion pudo realizarse
// False en caso contrario.
// PRE: el iterador fue creado.
// POST: el iterador hace referencia al siguiente nodo de la lista.
bool lista_iter_avanzar(lista_iter_t *iter);

// Devuelve el dato que se encuentra en la misma posicion que el iterador en la lista.
// PRE: el iterador fue creado.
void *lista_iter_ver_actual(const lista_iter_t *iter);

// Devuelve true si el iterador se encuentra al final de la lista.
// false en caso contrario.
// PRE: el iterador fue creado.
bool lista_iter_al_final(const lista_iter_t *iter);

// Destruye el iterador.
// PRE: el iterador fue creado.
// POST: se destruye el iterador.
void lista_iter_destruir(lista_iter_t *iter);



/* ******************************************************************
 *                    PRIMITIVAS EN COMUN: ITERADOR-LISTA
 * *****************************************************************/

// Inserta un elemento en la lista asociada al iterador, el iterador mantiene
// su posicion en el nuevo elemento agregado.
// Pre: el iterador y la lista fueron creados.
// Post: devuelve una lista con el elemento en cuestion agregado.
// El largo de la lista se incrementa en uno.
bool lista_insertar(lista_t *lista, lista_iter_t *iter, void *dato);

// Elimina un elemento en la lista asociada al iterador, dejando al iterador
// en la posicion posterior al elemento eliminado
// Pre: el iterador y la lista fueron creados.
// Post: devuelve una lista con el elemento en cuestion eliminado.
// El largo de la lista decrece en uno.
void *lista_borrar(lista_t *lista, lista_iter_t *iter);

#endif // LISTA_H
